import QtQuick 2.7

import Common 1.0
import Utils 1.0

// =============================================================================
// Helper to handle button click outside an item.
// =============================================================================

Item {
	id: mainItem
	
	// ---------------------------------------------------------------------------
	
	property bool _mouseAlwaysOutside
	property var _mouseArea: null
	
	// ---------------------------------------------------------------------------
	
	// When emitted, returns a function to test if the click
	// is on a specific item. It takes only a item parameter.
	signal pressed (var pointIsInItem)
	
	// ---------------------------------------------------------------------------
	
	function _createMouseArea () {
		var parent = Utils.getTopParent(mainItem, true)
		
		if (_mouseArea == null) {
			_mouseArea = builder.createObject()
		}
		
		_mouseArea.parent = parent
		
		// Must be true if a fake parent is used and if `mouseArea`
		// is not in the same window that `item`.
		_mouseAlwaysOutside =
				_mouseArea.parent !== Utils.getTopParent(mainItem)
	}
	
	function _deleteMouseArea () {
		if (_mouseArea != null) {
			_mouseArea.destroy()
			_mouseArea = null
		}
	}
	
	// ---------------------------------------------------------------------------
	
	// It's necessary to use a `enabled` variable.
	// See: http://doc.qt.io/qt-5/qml-qtqml-component.html#completed-signal
	//
	// The creation order of components in a view is undefined,
	// so the mouse area must be created only when the target component
	// was completed.
	Component.onCompleted: enabled && _createMouseArea()
	Component.onDestruction: _deleteMouseArea()
	
	onEnabledChanged: {
		_deleteMouseArea()
		
		if (enabled) {
			_createMouseArea()
		}
	}
	
	Component {
		id: builder
		
		MouseArea {
			id: area
			cursorShape: Qt.ArrowCursor
			preventStealing: true
			property var _timeout
			
			function _checkPosition (positionEvent) {
				// Propagate event.
				positionEvent.accepted = false
				
				// Click is outside or not.
				if (
						_mouseAlwaysOutside ||
						!Utils.pointIsInItem(area, mainItem, positionEvent)
						) {
					if (_timeout != null) {
						// Remove existing timeout to avoid the creation of
						// many children.
						Utils.clearTimeout(_timeout)
					}
					
					// Use a asynchronous call that is executed
					// after the propagated event.
					//
					// It's useful to ensure the window's context is not
					// modified with the positionEvent before the `onPressed`
					// call.
					//
					// The timeout is destroyed with the `MouseArea` component.
					_timeout = Utils.setTimeout(area, 0, mainItem.pressed.bind(
													this,
													(function (point, item) {
														return Utils.pointIsInItem(area, item, point)
													}).bind(this, { x: positionEvent.x, y: positionEvent.y })
													))
				}
			}
			
			anchors.fill: parent
			propagateComposedEvents: true
			z: Constants.zMax
			
			onPressed: _checkPosition.call(area, mouse)
			onWheel: _checkPosition.call(area, wheel)
		}
	}
}
